package com.apobates.jforum2.troll.replies.controller;

import com.apobates.jforum2.troll.regular.ImageIOMeta;
import com.apobates.jforum2.troll.replies.biz.PostsMoodRecordsService;
import com.apobates.jforum2.troll.replies.biz.PostsService;
import com.apobates.jforum2.troll.replies.entity.MoodCollectResult;
import com.apobates.jforum2.troll.replies.entity.Posts;
import com.apobates.jforum2.troll.replies.mapper.ReplyMoodVoMapperEntity;
import com.apobates.jforum2.troll.replies.mapper.ReplyVoMapperEntity;
import com.apobates.jforum2.troll.replies.stub.vo.ReplyMoodVo;
import com.apobates.jforum2.troll.replies.stub.vo.ReplyVo;
import com.apobates.jforum2.troll.utils.core.Commons;
import com.apobates.jforum2.troll.utils.core.EntityPageResult;
import com.apobates.jforum2.troll.utils.core.ResponseResult;
import com.apobates.jforum2.troll.utils.core.api.ActionEventCulpritor;
import com.apobates.jforum2.troll.utils.persistence.Page;
import com.apobates.jforum2.troll.utils.persistence.PageRequest;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 回复Api
 *
 * @author xiaofanku
 * @since 20201116
 */
@RestController
@RequestMapping("/posts")
public class PostsController {
    @Autowired
    private PostsService postsService;
    @Autowired
    private PostsMoodRecordsService postsMoodRecordsService;
    @Value("${img.bucket.domain}")
    private String imageBucketDomain;
    @Value("${img.bucket.upload.direct}")
    private String imageBucketUploadDirect;
    private final static Logger logger = LoggerFactory.getLogger(PostsController.class);

    //0:从话题移动中分离出来的事务
    @PutMapping(value="/reset/topic/{id}", consumes="application/x-www-form-urlencoded")
    public ResponseEntity<String> balanceReplyTopic(@RequestParam("target")long targetBoardId, @RequestParam("targetBoardGroup")int targetBoardGroupId, @PathVariable("id")long topicId){
        Supplier<Integer> resultFun = ()->postsService.toggleReplyTopic(topicId, targetBoardId, targetBoardGroupId);
        ResponseResult<String> rr = ResponseResult.ofIntegerResult(resultFun, "更新回复所属的话题失败");
        return ResponseEntity.status(rr.getCode()).contentType(MediaType.APPLICATION_JSON).body(rr.getEntity());
    }
    
    //1:从创建话题中分离出来的事务
    @PutMapping(value="/entry/topic/{id}", consumes="application/x-www-form-urlencoded")
    public ResponseEntity<String> entryTopicContent(
            @PathVariable("id")long topicId,
            @RequestParam("content")String topicContent, 
            @RequestParam("board")long boardId, 
            @RequestParam("boardgroup")int boardGroupId, 
            @RequestParam("member") long memberId,
            @RequestParam("nickname") String memberNickname,
            @RequestParam("token") String token,
            @RequestParam("ip") String ipAddr){
        ActionEventCulpritor culpritor = getInstance(memberId, memberNickname, ipAddr, token);
        Posts posts = postsService.entry(boardGroupId, boardId, topicId, topicContent, getImageIOMeta(), culpritor);
        Supplier<Optional<Long>> resultFun = ()->Optional.ofNullable(posts).map(Posts::getId);
        ResponseResult<String> rr = ResponseResult.ofLongResult(resultFun, "话题内容创建失败");
        return ResponseEntity.status(rr.getCode()).contentType(MediaType.APPLICATION_JSON).body(rr.getEntity());
    }
    //3:从创建话题编辑中分离出来的事务
    @PutMapping(value="/modify/topic/{id}", consumes="application/x-www-form-urlencoded")
    public ResponseEntity<String> modifyTopicContent(
            @PathVariable("id")long topicId,
            @RequestParam("content")String topicContent,
            @RequestParam("member") long memberId,
            @RequestParam("nickname") String memberNickname){
        Supplier<Optional<Boolean>> resultFun = ()->postsService.modifyTopic(topicId, topicContent, memberId, memberNickname, getImageIOMeta());
        ResponseResult<String> rr = ResponseResult.ofBoolean(resultFun, "更新话题内容失败");
        return ResponseEntity.status(rr.getCode()).contentType(MediaType.APPLICATION_JSON).body(rr.getEntity());
    }
    //4:查看指定回复
    @GetMapping("/{id}")
    public ResponseEntity<ReplyVo> get(@PathVariable("id")long postsId){
        Supplier<Optional<Posts>> rs = ()->(postsId>0)?postsService.get(postsId):Optional.empty();
        ResponseResult<ReplyVo> rr = ResponseResult.ofEntityVo(rs, new ReplyVoMapperEntity());
        return ResponseEntity.status(rr.getCode()).contentType(MediaType.APPLICATION_JSON).body(rr.getEntity());
    }
    //5:移至Nest实现
    //@GetMapping("/{id}/fold/{topic}")
    //public Response<ReplyVo> getCascade(@PathVariable("id")long postsId, @PathVariable("topic")long topicId){
    //    Optional<PostsReplica> posts = (postsId>0 && topicId>0)?postsService.get(postsId, topicId):Optional.empty();
    //    return ResponseResult.ofOptional(new ReplyCollectThreadsVoMapperEntity().transform(posts)).toJson();
    //}
    
    //6:统计指定回复者在话题中的回复次数, 1楼不在统计之列.忽略状态值
    @GetMapping("/replies/{topic}/{member}")
    public long countRepliesSize(@PathVariable("topic") long topicId, @PathVariable("member") long memberId){
        long r = postsService.countRepliesSize(topicId, memberId);
        return r; //ResponseResult.ofLong(r).toJson();
    }
    //7:查看指定话题最近的回复,忽略状态值;以entryDateTime倒序 服务于策略检查
    @GetMapping("/recent/{topic}")
    public List<ReplyVo> getRecentForTopicIgnoreStatus(@PathVariable("topic") long topicId, @RequestParam("size") int minInterruptSize){
        Stream<Posts> r = postsService.getRecentForTopicIgnoreStatus(topicId, minInterruptSize);
        return r.map(ReplyVoMapperEntity.mapper()).collect(Collectors.toList());
    }
    //8:移除回复
    @PutMapping(value="/{id}/remove", consumes="application/x-www-form-urlencoded")
    public boolean delReply(@PathVariable("id") long postsId,
                   @RequestParam("member") long memberId,
                   @RequestParam("nickname") String memberNickname,
                   @RequestParam("token") String token,
                   @RequestParam("ip") String ipAddr){
        Optional<Boolean> r = postsService.remove(postsId, getInstance(memberId, memberNickname, ipAddr, token));
        return r.orElse(false);
    }
    //9:创建回复
    @PostMapping(value="/create", consumes="application/x-www-form-urlencoded")
    public ResponseEntity<ReplyVo> createReply(
            @RequestParam("volumes") int volumesId,
            @RequestParam("board") long boardId,
            @RequestParam("threads") long topicId,
            @RequestParam("quote") long quotePostsId,
            @RequestParam("content") String content,
            @RequestParam("scale") String scale,
            @RequestParam("member") long memberId,
            @RequestParam("nickname") String memberNickname,
            @RequestParam("token") String token,
            @RequestParam("ip") String ipAddr){
        logger.error("[replies-api]CTL start reply topic");
        ActionEventCulpritor culpritor = getInstance(memberId, memberNickname, ipAddr, token);
        String postsContent = getRealPostsContent(quotePostsId, content, scale);
        Posts posts = postsService.create(volumesId, boardId, topicId, postsContent, getImageIOMeta(), culpritor);
        Supplier<Optional<Posts>> resultFun = ()-> Optional.ofNullable(posts);
        ResponseResult<ReplyVo> rr = ResponseResult.ofEntityVo(resultFun, new ReplyVoMapperEntity());
        return ResponseEntity.status(rr.getCode()).contentType(MediaType.APPLICATION_JSON).body(rr.getEntity());
    }
    //10:查看指定的回复, 并对内容进行解码(编辑内容)
    @GetMapping("/{id}/content")
    public ResponseEntity<ReplyVo> getPostsContentForEdit(@PathVariable("id") long postsId){
        Supplier<Optional<Posts>> rs = ()->postsService.getPostsContentForEdit(postsId, getImageIOMeta());
        ResponseResult<ReplyVo> rr = ResponseResult.ofEntityVo(rs, new ReplyVoMapperEntity());
        return ResponseEntity.status(rr.getCode()).contentType(MediaType.APPLICATION_JSON).body(rr.getEntity());
    }
    //11:查看话题最近的回复,不包括楼主的回复,并对回复内容进行解码(RSS)
    @GetMapping("/rss/{topic}")
    public List<ReplyVo> getRecentForRSS(@PathVariable("topic") long topicId, @RequestParam("size") int showSize){
        Stream<Posts> rs = postsService.getRecentForRSS(topicId, showSize, getImageIOMeta(), false);
        return rs.map(ReplyVoMapperEntity.mapper()).collect(Collectors.toList());
    }
    //12:查看话题中指定会员的所有回复,不包括楼主的话题内容并对回复内容进行图片解码
    @GetMapping("/threads/{topic}/{filterMember}/{scale}/{page}/{number}")
    public EntityPageResult<ReplyVo> getRepliesOrFilterAuthor(
            @PathVariable("topic") long topicId,
            @PathVariable("filterMember") long filterMemberId,
            @PathVariable("scale") String imageScale,
            @PathVariable("page") int page,
            @PathVariable("number") int pageSize,
            @RequestParam(value="sort", required=false, defaultValue="0")int sortCategory){
        //R:ForumReplierDigest
        Page<Posts> rs = postsService.getAllSortReplyFilterAuthor(topicId, filterMemberId, sortCategory, new PageRequest(page, pageSize), getImageIOMeta(), true, imageScale);
        //
        ResponseResult<EntityPageResult<ReplyVo>> rr = ResponseResult.PageResultBuilder.<ReplyVo,Posts>getInstance(page, pageSize)
                .from(rs.getTotalElements(), rs.getResult())
                .build(ReplyVoMapperEntity.mapper());
        return rr.getData();
    }
    //13:举报回复(移至Nest实现)
    
    //14:编辑回复
    @PutMapping(value="/{id}/modify", consumes="application/x-www-form-urlencoded")
    public ResponseEntity<ReplyVo> modifyReply(@PathVariable("id") long postsId,
                     @RequestParam("content") String content,
                     @RequestParam("member") long memberId,
                     @RequestParam("nickname") String memberNickname,
                     @RequestParam("token") String token,
                     @RequestParam("ip") String ipAddr){
        Supplier<Optional<Posts>> rs = ()->{
            Optional<Posts> tmp = Optional.empty();
            boolean status = postsService.edit(postsId, content, getImageIOMeta(), getInstance(memberId, memberNickname, ipAddr, token)).orElse(false);
            if(status) {
                tmp = postsService.get(postsId);
            }
            return tmp;
        };
        ResponseResult<ReplyVo> rr = ResponseResult.ofEntityVo(rs, new ReplyVoMapperEntity());
        return ResponseEntity.status(rr.getCode()).contentType(MediaType.APPLICATION_JSON).body(rr.getEntity());
    }
    //15:创建喜好记录.若会员已对回复的喜好记录存在方法会删除并返回成功
    //-1表示删除喜好,大于0表示喜好增加成功,0喜好增加失败
    //200 表示操作成功(DEL表示删除,ADD表示增加), 417 表示操作失败
    @PostMapping(value="/{id}/mood", consumes="application/x-www-form-urlencoded")
    public ResponseEntity<String> toggleMoodRecord(@PathVariable("id") long postsId,
                        @RequestParam("threads")long topicId,
                        @RequestParam("mood") int moodStatus,
                        @RequestParam("member") long memberId,
                        @RequestParam("nickname") String memberNickname,
                        @RequestParam("token") String token,
                        @RequestParam("ip") String ipAddr){
        logger.error("[replies-api]CTL start mood posts");
        boolean liked = (moodStatus == 1);
        ActionEventCulpritor culpritor = getInstance(memberId, memberNickname, ipAddr, token);
        logger.error(String.format("[replies-api]mood action member:%d, mood:%b, posts:%d, topic:%d", memberId, liked, postsId, topicId));
        long id = postsMoodRecordsService.toggleMoodRecord(postsId, topicId, liked, culpritor);
        logger.error("[replies-api] mood posts result:"+id);
        ResponseResult<String> ins = null;
        if(-1 == id){
            ins = ResponseResult.ofString("DEL", "喜好取消成功");
        }else if(id>0){
            ins = ResponseResult.ofString("ADD", "喜好增加成功");
        }else {
            ins = ResponseResult.ofString(null, "喜好增加失败");
        }
        //
        logger.error("[replies-api]outprint mood posts response start");
        return ResponseEntity.status(ins.getCode()).contentType(MediaType.APPLICATION_JSON).body(ins.getEntity());
    }
    //16:查看指定回复的喜好记录
    @GetMapping("/threads/{topic}/{id}/mood")
    public ResponseEntity<ReplyMoodVo> getMoodRecordByPosts(@PathVariable("id") long postsId, @PathVariable("topic") long topicId){
        Supplier<Optional<MoodCollectResult>> rs = ()->postsMoodRecordsService.getByPostsId(topicId, postsId);
        ResponseResult<ReplyMoodVo> rr = ResponseResult.ofEntityVo(rs, new ReplyMoodVoMapperEntity());
        return ResponseEntity.status(rr.getCode()).contentType(MediaType.APPLICATION_JSON).body(rr.getEntity());
    }
    //17:查看指定的回复喜好汇总记录
    @PostMapping(value="/mood/query", consumes="application/x-www-form-urlencoded")
    public List<ReplyMoodVo> getByPosts(@RequestParam("threads")long topicId, @RequestParam("records") String postsIdString){
        Set<Long> postsIdSet = Commons.toLongSet(postsIdString);
        if (null == postsIdSet || postsIdSet.isEmpty()) {
            return Collections.emptyList();
        }
        List<MoodCollectResult> data = postsMoodRecordsService.getByPosts(topicId, postsIdSet);
        return data.stream().map(ReplyMoodVoMapperEntity.mapper()).collect(Collectors.toList());
    }
    
    //18:查看指定话题的内容
    @GetMapping("/threads/{topic}/content")
    public ResponseEntity<ReplyVo> getOneFloorContent(@PathVariable("topic") long topicId){
        Supplier<Optional<Posts>> rs = ()->postsService.getTopicContent(topicId);
        ResponseResult<ReplyVo> rr = ResponseResult.ofEntityVo(rs, new ReplyVoMapperEntity());
        return ResponseEntity.status(rr.getCode()).contentType(MediaType.APPLICATION_JSON).body(rr.getEntity());
    }
    //19:查看指定话题的内容并解码内容中的图片
    @GetMapping("/threads/{topic}/content/decode")
    public ResponseEntity<ReplyVo> getOneFloorDecodeContent(@PathVariable("topic") long topicId, @RequestParam(value="scale", required=false, defaultValue="auto") String imageScale){
        Supplier<Optional<Posts>> rs = ()->postsService.getTopicContent(topicId, getImageIOMeta(), true, imageScale);
        ResponseResult<ReplyVo> rr = ResponseResult.ofEntityVo(rs, new ReplyVoMapperEntity());
        return ResponseEntity.status(rr.getCode()).contentType(MediaType.APPLICATION_JSON).body(rr.getEntity());
    }
    //引用回复时,引用的内容
    private String quoteContent(Optional<Posts> quotePosts) {
        if (!quotePosts.isPresent()) {
            return "";
        }
        Posts p = quotePosts.get();
        String t = "<blockquote><strong>引用<a href=\"%s\">%s</a> %s 的回复</strong><br/>%s</blockquote>";
        String quoteUrl = ReplyVoMapperEntity.generateLink(p);
        String quoteContent = (p.isNormal()) ? p.getContent() : "<p>回复内容已被屏蔽</p>";
        return String.format(t,
                quoteUrl,
                p.getFloorNumber() + "楼",
                p.getMemberNickname(),
                quoteContent);
    }

    //前补引用的内容
    private String getRealPostsContent(long quotePostsId, String formPostsContent, String imageScale) {
        String postsContent = formPostsContent;
        //
        if (quotePostsId > 0) {
            String quotePostsContent = quoteContent(postsService.getPostsContentForQuote(quotePostsId, getImageIOMeta(), false, imageScale));
            postsContent = quotePostsContent + postsContent;
        }
        return postsContent;
    }

    private ImageIOMeta getImageIOMeta(){
        return new ImageIOMeta(){
            @Override
            public String getImageBucketDomain() {
                return imageBucketDomain;
            }

            @Override
            public String getUploadImageDirectName() {
                return imageBucketUploadDirect;
            }
        };
    }
    public static ActionEventCulpritor getInstance(final long memberId, final String memberNickname, final String ipAddr, final String token) {
        return new ActionEventCulpritor() {
            @Override
            public long getMemberId() {
                return memberId;
            }

            @Override
            public String getMemberNickname() {
                return memberNickname;
            }

            @Override
            public String getIpAddr() {
                return ipAddr;
            }

            @Override
            public String getToken() {
                return token;
            }

            @Override
            public String getUserAgent() {
                return "";
            }
        };
    }
}
/*
/reply/{id}
/reply/{id}/fold/{topic}
/reply/{id}/remove
/reply/{id}/content
/reply/{id}/report
/reply/{id}/modify
/reply/{id}/mood
/reply/mood/query
/reply/replies/{topic}/{member}
/reply/recent/{topic}
/reply/create
/reply/rss/{topic}
/reply/threads/{topic}/{id}/mood
/reply/threads/{topic}/{filterMember}/{scale}/{page}/{number}
* */